﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using EmbeddedLanguage.SubProcessors;
using EmbeddedLanguage.Attributes;

namespace EmbeddedLanguage
{
    public static class ObjectEx
    {

        public const string RootNS = "EmJs";

        public static TMe AssignStaticAct_1x0<TMe, TInput1>(this TMe m, out Action<TInput1> act, Expression<Action<TInput1>> expr)
        {
            act = (input1) => CompiledStaticExpressionCache_1x0<TInput1>.GetCompiledAction(expr).Invoke(input1);
            return m;
        }

        public static TMe AssignStaticAct_2x0<TMe, TInput1, TInput2>(this TMe m, out Action<TInput1, TInput2> act, Expression<Action<TInput1, TInput2>> expr)
        {
            act = (input1, input2) => CompiledStaticExpressionCache_2x0<TInput1, TInput2>.GetCompiledAction(expr).Invoke(input1, input2);
            return m;
        }

        public static TMe AssignStaticMethod_0x1<TMe, TOut>(this TMe m, out Func<TOut> fun, Func<TOut> CompiledStaticFunc)
        {
            fun = () => CompiledStaticFunc.Invoke();
            return m;
        }

        public static TMe AssignStaticMethod_1x1<TMe, TInput1, TOut>(this TMe m, out Func<TInput1, TOut> fun, Func<TInput1, TOut> CompiledStaticFunc)
        {
            fun = input1 => CompiledStaticFunc.Invoke(input1);
            return m;
        }

        public static TMe AssignStaticFunc_1x1<TMe, TInput1, TOut>(this TMe m, out Func<TInput1, TOut> fun, Expression<Func<TInput1, TOut>> expr)
        {
            var fnGen = CompiledStaticExpressionCache_1x1<TInput1, TOut>.GetCompiledFunc(expr);
            fun = (input1) => fnGen.Invoke(input1);
            return m;
        }

        

        public static TMe AssignStaticFunc_2x1<TMe, TInput1, TInput2, TOut>(this TMe m, out Func<TInput1, TInput2, TOut> fun, Expression<Func<TInput1, TInput2, TOut>> expr)
        {
            fun = (input1, input2) => CompiledStaticExpressionCache_2x1<TInput1, TInput2, TOut>.GetCompiledFunc(expr).Invoke(input1, input2);
            return m;
        }

        public static TMe Associate_2x1<TMe, TInput1, TInput2, TOut>(this TMe me, Func<TInput1, TInput2, TOut> fun, Del_2x1<TInput1, TInput2, TOut> deleg)
        {
            return me;
        }

       

        [SubProcessor(
            JSSubProcessorType = typeof(AssignJSProcessor)
        )]
        public static TMe Assign<TMe, TObj>(this TMe me, out TObj objDest, TObj objSource)
        {
            objDest = objSource;
            return me;
        }

        public static TMe Assign<TMe, TObj>(this TMe me, TObj objValue, Func<TMe, TObj> Getter)
        {
            TObj objDest = Getter(me);
            Assign(me, out objDest, objValue);
            return me;
        }


        
        public static TMe Do<TMe>(this TMe me, Action<TMe> action)
        {
            action(me);
            return me;
        }

        public static TMe DoRecursively<TMe>(this TMe me, Func<TMe, bool> BreakCondition, Action<TMe> BeforeRecursiveCall, Action<TMe> AfterRecursiveCall)
        {
            if (BreakCondition(me)) return me;
            if(BeforeRecursiveCall!=null) BeforeRecursiveCall(me);
            me.DoRecursively(BreakCondition, BeforeRecursiveCall, AfterRecursiveCall);
            if(AfterRecursiveCall!=null)  AfterRecursiveCall(me);
            return me;
        }

        public static TMe DoOn<TMe, TObj>(this TMe me, TObj obj, Action<TObj> action)
        {
            return me;
        }

        public static TMe DoOn<TMe, TObj>(this TMe me, TObj obj, Func<TObj, TObj> func)
        {
            return me;
        }

        public static TMe Up<TMe>(this TMe me, PropBinder<TMe> Prop)
        {
            Prop.eq(me);
            return me;
        }

        
        public static TMe AttachMethod_0X0<TMe>(this TMe me, Func<TMe, Action> dest, Func<TMe, Action> src)
        {
            var destFunc = dest(me);
            var srcFunc = src(me);
            me.Assign(out destFunc, srcFunc);
            return me;
        }

       
        public static TMe AttachMethod_0X1<TMe, TOut>(this TMe me, Func<TMe, Func<TOut>> dest, Func<TMe, Func<TOut>> src)
        {
            var destFunc = dest(me);
            var srcFunc = src(me);
            me.Assign(out destFunc, srcFunc);
            return me;
        }

        [SubProcessor(
            JSSubProcessorType=typeof(IfJSProcessor)
        )]
        public static TMe If<TMe>(this TMe me, Func<TMe, bool> Condition, Action<TMe> DoIf, Action<TMe> DoElse)
        {
            bool bCondition = Condition(me);
            if (bCondition)
            {
                if (DoIf != null)
                {
                    DoIf(me);
                }
            }
            else if (DoElse != null)
            {
                DoElse(me);
            }

            return me;
        }
    }

   

    
}
